home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / hexedit105 folder / HexEditSource / Source / EditWindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-13  |  48.4 KB  |  1,839 lines  |  [TEXT/KAHL]

  1. /*********************************************************************
  2.  * EditWindow.c
  3.  *
  4.  * HexEdit, a simple hex editor
  5.  * copyright 1993, Jim Bumgardner
  6.  *********************************************************************/
  7. #include "HexEdit.h"
  8. #include "Folders.h"
  9. #include <stdio.h>
  10.  
  11. // Create a new main window using a 'WIND' template from the resource fork
  12. //
  13.  
  14. Boolean         gCursorFlag;
  15. Rect            gCursRect;
  16. BitMap            gBitMap;
  17. Preferences        gPrefs = {AM_Lo, false, true};
  18. short            gForkMode=FM_Smart,gHighChar='~',gOverwrite;
  19. THPrint            gHPrint;
  20. static char        gBuffer[80];
  21. Cursor            gWatchCursor,gIBeamCursor;
  22. short            gMaxHeight=342;
  23.  
  24. void LoadPreferences(void)
  25. {
  26.     Handle    h;
  27.     h = GetResource(PrefResType, PrefResID);
  28.     if (h == NULL || ResError())
  29.         return;
  30.     BlockMove(*h, &gPrefs, sizeof(Preferences));
  31.     ReleaseResource(h);
  32.     if (gPrefs.asciiMode)
  33.         gHighChar = 255;
  34.     else
  35.         gHighChar = '~';
  36. }
  37.  
  38. void SavePreferences(void)
  39. {
  40.     Handle    h;
  41.     while ((h = GetResource(PrefResType, PrefResID)) != NULL) {
  42.         RmveResource(h);
  43.         DisposHandle(h);
  44.     }
  45.     h = NewHandle(sizeof(Preferences));
  46.     if (h == NULL) {
  47.         ErrorAlert(ES_Caution,"Not enough memory");
  48.     }
  49.     else {
  50.         BlockMove(&gPrefs, *h, sizeof(Preferences));
  51.         AddResource(h,PrefResType,PrefResID,"\pPreferences");
  52.         WriteResource(h);
  53.         ReleaseResource(h);
  54.     }
  55. }
  56.  
  57. void InitializeEditor()
  58. {
  59.     Rect                offRect;
  60.     OSErr                oe;
  61.     CursHandle            cH = NULL;
  62.  
  63.     if (ScrapInfo.scrapState < 0)
  64.         ZeroScrap();
  65.  
  66.     // Start Profiling
  67. #if PROFILE            // 6/15 Optional profiling support
  68.     freopen("profile.log","w",stdout);        // If console isn't wanted
  69.     InitProfile(200,200);
  70.     _profile = 0;
  71.     // cecho2file("profile.log",false,stdout);    // If console is wanted
  72. #endif
  73.     gMaxHeight = screenBits.bounds.bottom - screenBits.bounds.top;
  74.     if (gMaxHeight < 342)
  75.         gMaxHeight = 342;
  76.     SetRect(&offRect,0,0,MaxWindowWidth,gMaxHeight);
  77.     gBitMap.rowBytes = (((MaxWindowWidth-1)/32)+1)*4;
  78.     gBitMap.baseAddr = NewPtrClear( (long) gBitMap.rowBytes * gMaxHeight );
  79.     if (gBitMap.baseAddr == NULL)
  80.         ErrorAlert(ES_Stop,"Not enough memory");
  81.     gBitMap.bounds = offRect;
  82.  
  83.     cH = GetCursor(watchCursor);
  84.     if (cH)
  85.         gWatchCursor = **cH;
  86.     cH = GetCursor(iBeamCursor);
  87.     if (cH)
  88.         gIBeamCursor = **cH;
  89.  
  90.     PrOpen();
  91.     gHPrint = (THPrint) NewHandle(sizeof(TPrint));
  92.     if (gHPrint == NULL) {
  93.         ErrorAlert(ES_Stop,"Not enough memory");
  94.     }
  95.     PrintDefault(gHPrint);
  96.     PrClose();
  97.  
  98.     LoadPreferences();
  99. }
  100.  
  101. void CleanupEditor()
  102. {
  103.     if (gBitMap.baseAddr) {
  104.         DisposePtr(gBitMap.baseAddr);
  105.         gBitMap.baseAddr = NULL;
  106.     }
  107.     SavePreferences();
  108. }
  109.  
  110. void NewEditWindow(void)
  111. {
  112.     WindowPtr            theWindow;
  113.     EditWindowPtr        dWin;
  114.     OSErr                oe;
  115.     short                refNum=0;
  116.     Point                where={-1,-1};
  117.     HParamBlockRec        pb;
  118.     FSSpec                workSpec;
  119.     Rect                r;
  120.  
  121.     // Get the Template & Create the Window, it is set up in the resource fork
  122.     // to not be initially visible 
  123.  
  124.     dWin = (EditWindowPtr) NewPtrClear(sizeof(EditWindowRecord));
  125.     if (dWin == NULL) {
  126.         FSClose(refNum);
  127.         ErrorAlert(ES_Caution, "Can't allocate new window");
  128.         return;
  129.     }
  130.  
  131.     dWin->fork = FT_Data;
  132.     dWin->fileSize = 0L;
  133.     dWin->refNum = 0;
  134.  
  135.     // Initialize WorkSpec
  136.     workSpec = dWin->workSpec;
  137.     oe = FindFolder(-1, kTemporaryFolderType, kCreateFolder, 
  138.                     &workSpec.vRefNum,
  139.                     &workSpec.parID);
  140.     if (oe != noErr) {
  141.         OSErrorAlert(ES_Caution, "FindFolder", oe);
  142.         return;
  143.     }
  144.     BlockMove("\pUntitledw", workSpec.name, 10);
  145.     InsureNameIsUnique(&workSpec);
  146.     HCreate(workSpec.vRefNum,workSpec.parID,workSpec.name,CREATOR, '????');
  147.     if (oe != noErr) {
  148.         OSErrorAlert(ES_Caution, "HCreate", oe);
  149.         return;
  150.     }
  151.     oe = HOpen(workSpec.vRefNum,workSpec.parID,workSpec.name,fsRdWrPerm,&refNum);
  152.     if (oe != noErr) {
  153.         OSErrorAlert(ES_Caution, "HOpen", oe);
  154.         return;
  155.     }
  156.  
  157.     dWin->workSpec = workSpec;
  158.     dWin->workRefNum = refNum;
  159.     dWin->workBytesWritten = 0L;
  160.  
  161.     dWin->fileType = DEFFILETYPE;
  162.     dWin->creator = CREATOR;
  163.     dWin->creationDate = 0L;
  164.  
  165.     theWindow = InitObjectWindow(MainWIND, (ObjectWindowPtr) dWin,false);
  166.     if (theWindow == NULL)
  167.         ErrorAlert(ES_Stop,"Not enough memory");
  168.  
  169.     SizeWindow(theWindow,484+SBarSize-1-1,gMaxHeight-64,true);
  170.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 44);
  171.     OffsetRect(&r,3,41);
  172.     ((WStateData *)*((WindowPeek) theWindow)->dataHandle)->stdState = r;
  173.  
  174.     SetWTitle(theWindow, "\pUntitled");
  175.  
  176.     ((ObjectWindowPtr) theWindow)->Draw = MyDraw;
  177.     ((ObjectWindowPtr) theWindow)->Idle = MyIdle;
  178.     ((ObjectWindowPtr) theWindow)->HandleClick = MyHandleClick;
  179.     ((ObjectWindowPtr) theWindow)->Dispose = DisposeEditWindow;
  180.     ((ObjectWindowPtr) theWindow)->ProcessKey = MyProcessKey;
  181.     ((ObjectWindowPtr) theWindow)->Save = SaveContents;
  182.     ((ObjectWindowPtr) theWindow)->SaveAs = SaveAsContents;
  183.     ((ObjectWindowPtr) theWindow)->Revert = RevertContents;
  184.     
  185.     // Show the window
  186.     ShowWindow(theWindow);
  187.  
  188.     // Make it the current grafport
  189.     SetPort(theWindow);
  190.  
  191.     
  192.     dWin->linesPerPage = ((theWindow->portRect.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  193.     dWin->startSel = dWin->endSel = 0L;
  194.     dWin->editMode = EM_Hex;
  195.  
  196.     SetupScrollBars(dWin);
  197.  
  198.     dWin->firstChunk = NewChunk(0L,0L,0L, CT_Unwritten);
  199.     dWin->curChunk = dWin->firstChunk;
  200. }
  201.  
  202. #define DataItem        11
  203. #define RsrcItem        12
  204. #define SmartItem        13
  205.  
  206. /*SFReply        *gReplyPtr;*/
  207.  
  208. pascal int SourceDLOGHook(short item, DialogPtr theDialog)
  209. {
  210.     switch (item) {
  211.     case DataItem:
  212.     case RsrcItem:
  213.     case SmartItem:
  214.         SetControl(theDialog,gForkMode+DataItem,false);
  215.         gForkMode = item - DataItem;
  216.         SetControl(theDialog,gForkMode+DataItem,true);
  217.         return sfHookNullEvent;    /* Redraw the List */
  218.     case sfHookFirstCall:
  219.         SetControl(theDialog,gForkMode+DataItem,true);
  220.         return sfHookNullEvent;
  221. /*    case sfHookNullEvent:*/
  222. /*        {*/
  223. /*            Point    p;*/
  224. /*            short    t;*/
  225. /*            Handle    h;*/
  226. /*            Rect    r;*/
  227. /*            GetMouse(&p);*/
  228. /*            GetDItem(theDialog,DataItem,&t,&h,&r);            */
  229. /*            if (PtInRect(p,&r))*/
  230. /*                DebugStr("\pBoing!");*/
  231. /*        }*/
  232. /*        break;*/
  233.     }
  234.     return item;
  235. }
  236.  
  237. void AskEditWindow(void)
  238. {
  239.     SFReply                macSFReply;
  240.     FSSpec                fSpec;
  241.     long                procID;
  242.     Point                where = {-1,-1};
  243.  
  244.     // StandardGetFile(NULL, -1, NULL, &reply);
  245.     if (!gSys7Flag) {
  246.         where.h = 20;
  247.         where.v = 90;
  248.     }
  249.  
  250.     SFPGetFile(where, "\pFile to Open:", NULL, -1, NULL, (ProcPtr) SourceDLOGHook, 
  251.                 &macSFReply, GetFileDLOG, NULL);
  252.  
  253.     if (macSFReply.good) {
  254.         BlockMove(macSFReply.fName,fSpec.name,macSFReply.fName[0]+1);
  255.         GetWDInfo(macSFReply.vRefNum, &fSpec.vRefNum, &fSpec.parID, &procID);
  256.         OpenEditWindow(&fSpec);
  257.     }
  258.     MyAdjustMenus();
  259. }
  260.  
  261.  
  262.  
  263.  
  264. void OpenEditWindow(FSSpec *fsSpec)
  265. {
  266.     WindowPtr            theWindow;
  267.     EditWindowPtr        dWin;
  268.     OSErr                oe;
  269.     short                refNum=0;
  270.     Point                where={-1,-1};
  271.     HParamBlockRec        pb;
  272.     FSSpec                workSpec;
  273.     Rect                r;
  274.  
  275.     // Get the Template & Create the Window, it is set up in the resource fork
  276.     // to not be initially visible 
  277.  
  278.  
  279.     pb.fileParam.ioCompletion = 0l;
  280.     pb.fileParam.ioNamePtr = fsSpec->name;
  281.     pb.fileParam.ioVRefNum = fsSpec->vRefNum;
  282.     pb.fileParam.ioDirID = fsSpec->parID;
  283.     pb.fileParam.ioFDirIndex = 0;
  284.  
  285.     if ((oe = PBHGetFInfo(&pb,FALSE)) != noErr) {
  286.         OSErrorAlert(ES_Caution, "PBHGetFInfo", oe);
  287.         return;
  288.     }
  289.  
  290.     // fileSize = pb.fileParam.ioFlLgLen;    // Data Fork Length!!!!
  291.     // GetEOF(refNum,&fileSize);
  292.  
  293.     dWin = (EditWindowPtr) NewPtrClear(sizeof(EditWindowRecord));
  294.     if (dWin == NULL) {
  295.         FSClose(refNum);
  296.         ErrorAlert(ES_Caution, "Can't allocate new window");
  297.         return;
  298.     }
  299.  
  300.     if (gForkMode == FM_Data || (pb.fileParam.ioFlLgLen > 0 && gForkMode == FM_Smart)) {
  301.         // Open Data Fork
  302.         dWin->fork = FT_Data;
  303.         oe = HOpen(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  304.         if (oe == fnfErr) {
  305.             ParamText(fsSpec->name,"\pdata","\p","\p");
  306.             if (CautionAlert(NoForkALRT,NULL) != 2)
  307.                 return;
  308.             oe = HCreate(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,
  309.                         pb.fileParam.ioFlFndrInfo.fdCreator,
  310.                         pb.fileParam.ioFlFndrInfo.fdType);
  311.             if (oe != noErr) {
  312.                 OSErrorAlert(ES_Caution, "HCreate", oe);
  313.                 return;
  314.             }
  315.             oe = HOpen(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  316.         }
  317.         if (oe != noErr) {
  318.             OSErrorAlert(ES_Caution, "HOpen", oe);
  319.             return;
  320.         }
  321.         dWin->fileSize = pb.fileParam.ioFlLgLen;
  322.     }
  323.     else {
  324.         // Open Resource Fork
  325.         dWin->fork = FT_Resource;
  326.         oe = HOpenRF(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  327.         if (oe == fnfErr) {
  328.             ParamText(fsSpec->name,"\presource","\p","\p");
  329.             if (CautionAlert(NoForkALRT,NULL) != 2)
  330.                 return;
  331.             HCreateResFile(fsSpec->vRefNum,fsSpec->parID,fsSpec->name);
  332.             if ((oe = ResError()) != noErr) {
  333.                 OSErrorAlert(ES_Caution, "HCreateResFile", oe);
  334.                 return;
  335.             }
  336.             oe = HOpenRF(fsSpec->vRefNum,fsSpec->parID,fsSpec->name,fsRdPerm,&refNum);
  337.         }
  338.         if (oe != noErr) {
  339.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  340.             return;
  341.         }
  342.         dWin->fileSize = pb.fileParam.ioFlRLgLen;
  343.     }
  344.  
  345.     dWin->refNum = refNum;
  346.  
  347.     workSpec = *fsSpec;
  348.     oe = FindFolder(-1, kTemporaryFolderType, kCreateFolder, 
  349.                     &workSpec.vRefNum,
  350.                     &workSpec.parID);
  351.     if (oe != noErr) {
  352.         OSErrorAlert(ES_Caution, "FindFolder", oe);
  353.         return;
  354.     }
  355.     if (workSpec.name[0] < 31) {
  356.         workSpec.name[0]++;
  357.         workSpec.name[workSpec.name[0]] = 'w';
  358.     }
  359.     else
  360.         workSpec.name[31] ^= 0x10;
  361.     InsureNameIsUnique(&workSpec);
  362.     oe = HCreate(workSpec.vRefNum,workSpec.parID,workSpec.name,CREATOR, '????');
  363.     if (oe != noErr) {
  364.         OSErrorAlert(ES_Caution, "HCreate", oe);
  365.         return;
  366.     }
  367.     oe = HOpen(workSpec.vRefNum,workSpec.parID,workSpec.name,fsRdWrPerm,&refNum);
  368.     if (oe != noErr) {
  369.         OSErrorAlert(ES_Caution, "HOpen", oe);
  370.         return;
  371.     }
  372.  
  373.     dWin->workSpec = workSpec;
  374.     dWin->workRefNum = refNum;
  375.     dWin->workBytesWritten = 0L;
  376.  
  377.     dWin->fileType = pb.fileParam.ioFlFndrInfo.fdType;
  378.     dWin->creator = pb.fileParam.ioFlFndrInfo.fdCreator;
  379.     dWin->creationDate =  pb.fileParam.ioFlCrDat;
  380.  
  381.     theWindow = InitObjectWindow(MainWIND, (ObjectWindowPtr) dWin,false);
  382.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 64);
  383.  
  384.     dWin->linesPerPage = ((r.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  385.  
  386.     if ((dWin->linesPerPage-1) * 16L > dWin->fileSize)
  387.         r.bottom -= LineHeight * (((dWin->linesPerPage-1) * 16L) - dWin->fileSize)/16;
  388.     if (r.bottom < SBarSize+TopMargin+BotMargin+HeaderHeight+LineHeight*3)
  389.         r.bottom = SBarSize+TopMargin+BotMargin+HeaderHeight+LineHeight*3;
  390.  
  391.     SizeWindow(theWindow,r.right-1,r.bottom,true);
  392.     SetRect(&r, 0, 0, MaxWindowWidth+SBarSize-1, gMaxHeight - 44);
  393.     OffsetRect(&r,3,41);
  394.     ((WStateData *) *((WindowPeek) theWindow)->dataHandle)->stdState = r;
  395.     SetWTitle(theWindow, fsSpec->name);
  396.     dWin->fsSpec = *fsSpec;
  397.     dWin->destSpec = dWin->fsSpec;
  398.  
  399.     ((ObjectWindowPtr) theWindow)->Draw = MyDraw;
  400.     ((ObjectWindowPtr) theWindow)->Idle = MyIdle;
  401.     ((ObjectWindowPtr) theWindow)->HandleClick = MyHandleClick;
  402.     ((ObjectWindowPtr) theWindow)->Dispose = DisposeEditWindow;
  403.     ((ObjectWindowPtr) theWindow)->ProcessKey = MyProcessKey;
  404.     ((ObjectWindowPtr) theWindow)->Save = SaveContents;
  405.     ((ObjectWindowPtr) theWindow)->SaveAs = SaveAsContents;
  406.     ((ObjectWindowPtr) theWindow)->Revert = RevertContents;
  407.     
  408.     // Show the window
  409.     ShowWindow(theWindow);
  410.  
  411.     // Make it the current grafport
  412.     SetPort(theWindow);
  413.     
  414.     dWin->linesPerPage = ((theWindow->portRect.bottom - SBarSize) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  415.     dWin->startSel = dWin->endSel = 0L;
  416.     dWin->editMode = EM_Hex;
  417.  
  418.     SetupScrollBars(dWin);
  419.  
  420.     LoadFile(dWin);
  421. }
  422.  
  423. void DisposeEditWindow(WindowPtr theWindow)
  424. {
  425.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  426.  
  427.     UnloadFile(dWin);
  428.     if (dWin->refNum)
  429.         FSClose(dWin->refNum);
  430.     if (dWin->workRefNum) {
  431.         FSClose(dWin->workRefNum);
  432.         HDelete(dWin->workSpec.vRefNum, dWin->workSpec.parID, dWin->workSpec.name);
  433.     }
  434.     DefaultDispose(theWindow);
  435.     MyAdjustMenus();
  436. }
  437.  
  438. Boolean    CloseEditWindow(WindowPtr theWindow)
  439. {
  440.     Str63            fileName;
  441.     EditWindowPtr    dWin = (EditWindowPtr) theWindow;
  442.  
  443.     MySetCursor(C_Arrow);
  444.  
  445.     if (dWin->dirtyFlag) {
  446.         GetWTitle(theWindow, fileName);
  447.         ParamText(fileName, "\p","\p","\p");
  448.         switch (Alert(SaveChangesALRT, NULL)) {
  449.         case OK:        
  450.             SaveContents(theWindow);    
  451.             break;
  452.         case Cancel:
  453.             return false;
  454.         case 3:
  455.             // Discard
  456.             break;
  457.         }
  458.     }
  459.     ((ObjectWindowPtr) dWin)->Dispose(theWindow);
  460.     return true;
  461. }
  462.  
  463. Boolean CloseAllEditWindows()
  464. {
  465.     WindowPeek    wp;
  466.     wp = (WindowPeek) FrontWindow();
  467.     while (wp) {
  468.         if (wp->windowKind < 0)
  469.              CloseDeskAcc(wp->windowKind);
  470.         else if (wp->refCon == MyWindowID) {
  471.             if (!CloseEditWindow((WindowPtr) wp))
  472.                 return false;
  473.         }
  474.         else if ((WindowPtr) wp == gSearchWin) {
  475.             DisposDialog(gSearchWin);
  476.             gSearchWin = NULL;
  477.         }
  478.         else
  479.             return false;
  480.         wp = (WindowPeek) FrontWindow();
  481.     }
  482.     return true;
  483. }
  484.  
  485. // Respond to an update event - BeginUpdate has already been called.
  486. //
  487.  
  488. void MyDraw(WindowPtr theWindow)
  489. {
  490.     RgnHandle        rg1,rg2,rg3;
  491.     Rect            r3;
  492.  
  493.     rg1 = NewRgn();
  494.     rg2 = NewRgn();
  495.     rg3 = NewRgn();
  496.     RectRgn(rg1, &theWindow->portRect);
  497.     RectRgn(rg2, &gBitMap.bounds);
  498.     r3 = theWindow->portRect;
  499.     r3.right -= SBarSize-1;
  500.     r3.bottom -= SBarSize-1;
  501.     RectRgn(rg3, &r3);
  502.     SectRgn(rg2,rg3,rg2);    // Intersection of offscreen and valid content area
  503.     DiffRgn(rg1,rg2,rg1);    // Subtract from whole content area
  504.     EraseRgn(rg1);
  505.     DisposeRgn(rg1);
  506.     DisposeRgn(rg2);
  507.     DisposeRgn(rg3);
  508.     // Draw the grow icon in the corner
  509.     // EraseRect(&theWindow->portRect);
  510.     DrawControls(theWindow);
  511.     DrawGrowIcon(theWindow);
  512.     DrawPage((EditWindowPtr) theWindow);
  513.     UpdateOnscreen(theWindow);
  514. }
  515.  
  516. void UpdateOnscreen(WindowPtr theWindow)
  517. {
  518.     Rect            r1,r2,r3;
  519.     EditWindowPtr    dWin;
  520.  
  521.     gCursorFlag = false;
  522.     r1 = gBitMap.bounds;
  523.     r2 = theWindow->portRect;
  524.     r2.right -= SBarSize - 1;
  525.     r2.bottom -= SBarSize - 1;
  526.     SectRect(&r1,&r2,&r3);
  527.     SetPort(theWindow);
  528.     CopyBits(&gBitMap,&theWindow->portBits,&r3,&r3,srcCopy,0L);
  529.  
  530.     dWin = (EditWindowPtr) theWindow;
  531.     if (dWin->endSel > dWin->startSel && 
  532.         dWin->endSel >= dWin->editOffset &&
  533.         dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  534.         InvertSelection(dWin);
  535. }
  536.  
  537. void MyIdle(WindowPtr theWin, EventRecord *er)
  538. {
  539.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  540.     Boolean            frontWindowFlag;
  541.     Point            w;
  542.     frontWindowFlag = (theWin == FrontWindow() &&
  543.                         dWin->oWin.active);
  544.     if (frontWindowFlag) {
  545.         w = er->where;
  546.         SetPort(theWin);
  547.         GlobalToLocal(&w);
  548.         if (w.v >= HeaderHeight+TopMargin && 
  549.             w.v < HeaderHeight+TopMargin+(dWin->linesPerPage*LineHeight))
  550.         {
  551.                 if (w.h >= AddrPos+CharPos(HexStart) &&
  552.                     w.h < AddrPos+CharPos(HexStart)+(HexWidth<<4)) 
  553.                     MySetCursor(C_IBeam);
  554.                 else if (w.h >= AddrPos+CharPos(AsciiStart) &&
  555.                          w.h < AddrPos+CharPos(AsciiStart)+(CharWidth<<4))
  556.                     MySetCursor(C_IBeam);
  557.                 else
  558.                     MySetCursor(C_Arrow);
  559.         }
  560.         else
  561.             MySetCursor(C_Arrow);
  562.  
  563.         if (dWin->startSel == dWin->endSel) {
  564.             if ((Ticks & 0x1F) < 0x10)
  565.                 CursorOn(theWin);
  566.             else
  567.                 CursorOff(theWin);
  568.         }
  569.         if (gScrapCount != ScrapInfo.scrapCount) {
  570.             EditChunk    **nc;
  571.             Handle        h;
  572.             long        size,offset;
  573.             size = GetScrap(NULL, 'TEXT', &offset);
  574.             if (size > 0) {
  575.                 nc = NewChunk(size,0,0,CT_Unwritten);
  576.                 if (nc == NULL)
  577.                     ErrorAlert(ES_Caution,"Not enough memory for desktop scrap");
  578.                 else {
  579.                     ReleaseEditScrap(dWin, &gScrapChunk);
  580.                     gScrapChunk = nc;
  581.                     GetScrap((*gScrapChunk)->data,'TEXT',&offset);
  582.                     (*gScrapChunk)->lastCtr = 1;    // Flag as external
  583.                 }
  584.             }
  585.             gScrapCount = ScrapInfo.scrapCount;
  586.         }
  587.     }
  588. }
  589.  
  590.  
  591. // Respond to a mouse-click - highlight cells until the user releases the button
  592. //
  593. void MyHandleClick(WindowPtr theWin, Point where, EventRecord *er)
  594. {
  595.     Point    w;
  596.     long    pos;
  597.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  598.     long    anchorPos = -1,sPos,ePos;
  599.  
  600.     SetPort(theWin);
  601.     w = where;
  602.     GlobalToLocal(&w);
  603.     if (HandleControlClick(theWin,w))
  604.         return;
  605.     // Else handle editing chore
  606.     CursorOff(theWin);
  607.     if (w.v >= HeaderHeight+TopMargin && 
  608.         w.v < HeaderHeight+TopMargin+(dWin->linesPerPage*LineHeight))
  609.     {
  610.         do {
  611.             AutoScroll(dWin, w);
  612.  
  613.             if (w.h >= AddrPos+CharPos(HexStart) &&
  614.                 w.h < AddrPos+CharPos(HexStart)+(HexWidth<<4)) 
  615.             {
  616.  
  617.                 pos = ((w.v - (HeaderHeight+TopMargin))/LineHeight)*16 +
  618.                       (w.h - (AddrPos+CharPos(HexStart))+12) / HexWidth;
  619.                 dWin->editMode = EM_Hex;
  620.             }
  621.             else if (w.h >= AddrPos+CharPos(AsciiStart) &&
  622.                      w.h < AddrPos+CharPos(AsciiStart)+(CharWidth<<4))
  623.             {
  624.                 pos = ((w.v - (HeaderHeight+TopMargin))/LineHeight)*16 +
  625.                       (w.h - (AddrPos+CharPos(AsciiStart))+3) / CharWidth;
  626.                 dWin->editMode = EM_Ascii;
  627.             }
  628.             else {
  629.                 goto GetMouseLabel;
  630.             }
  631.             pos += dWin->editOffset;
  632.             if (pos < dWin->editOffset)
  633.                 pos = dWin->editOffset;
  634.             if (pos > dWin->editOffset+(dWin->linesPerPage<<4))
  635.                 pos = dWin->editOffset+(dWin->linesPerPage<<4);
  636.             if (pos > dWin->fileSize)
  637.                 pos = dWin->fileSize;
  638.             if (anchorPos == -1) {
  639.                 if (er->modifiers & shiftKey)
  640.                     anchorPos = (pos < dWin->startSel)? dWin->endSel : dWin->startSel;
  641.                 else
  642.                     anchorPos = pos;
  643.             }
  644.             sPos = pos < anchorPos? pos : anchorPos;
  645.             ePos = pos > anchorPos? pos : anchorPos;
  646.             if (ePos > dWin->fileSize)
  647.                 ePos = dWin->fileSize;
  648.  
  649.             if (sPos != dWin->startSel ||
  650.                 ePos != dWin->endSel) {
  651.                 dWin->startSel = sPos;
  652.                 dWin->endSel = ePos;
  653.                 UpdateOnscreen(theWin);
  654.             }
  655.  
  656.     GetMouseLabel:
  657.             GetMouse(&w);
  658.         } while (WaitMouseUp());
  659.     }
  660. }
  661.  
  662. void DrawHeader(EditWindowPtr dWin, Rect *r)
  663. {
  664.     TextFont(monaco);
  665.     TextSize(9);
  666.     TextFace(bold);
  667.     TextMode(srcCopy);
  668.  
  669.     MoveTo(r->left,r->top+HeaderHeight-1);
  670.     LineTo(r->right,r->top+HeaderHeight-1);
  671.  
  672.     MoveTo(20, r->top+HeaderHeight-DescendHeight-2);
  673.     if (gPrefs.decimalAddr)
  674.         sprintf(gBuffer,"Length: %7ld    Type: %4.4s    Creator: %4.4s    Fork: %s", 
  675.             dWin->fileSize,&dWin->fileType, &dWin->creator,
  676.             ((dWin->fork == FT_Data)? "data" : "rsrc"));
  677.     else
  678.         sprintf(gBuffer,"Length: %6lXh    Type: %4.4s    Creator: %4.4s    Fork: %s", 
  679.             dWin->fileSize,&dWin->fileType, &dWin->creator,
  680.             ((dWin->fork == FT_Data)? "data" : "rsrc"));
  681.     DrawText(gBuffer,0,strlen(gBuffer));
  682. }
  683.  
  684. void DrawFooter(EditWindowPtr dWin, Rect *r, short pageNbr, short nbrPages)
  685. {
  686.     unsigned long    tim;
  687.     DateTimeRec        dat;
  688.     Str31            fileName;
  689.  
  690.     TextFont(monaco);
  691.     TextSize(9);
  692.     TextFace(0);
  693.     TextMode(srcCopy);
  694.  
  695.     GetDateTime(&tim);
  696.     Secs2Date(tim,&dat);
  697.  
  698.     MoveTo(r->left,r->top);
  699.     LineTo(r->right,r->top);
  700.  
  701.     sprintf(gBuffer, "%02d/%02d/%02d %02d:%02d",
  702.         dat.month,dat.day,dat.year-1900,dat.hour,dat.minute);
  703.  
  704.     MoveTo(20, r->top+FooterHeight-DescendHeight-2);
  705.     DrawText(gBuffer,0,strlen(gBuffer));
  706.  
  707.     GetWTitle((WindowPtr) dWin, fileName);
  708.     sprintf(gBuffer,"File: %.*s", fileName[0],&fileName[1]);
  709.     MoveTo((r->left+r->right)/2 - TextWidth(gBuffer,0,strlen(gBuffer))/2,
  710.              r->top+FooterHeight-DescendHeight-2);
  711.     DrawText(gBuffer,0,strlen(gBuffer));
  712.     
  713.     sprintf(gBuffer,"%d of %d",pageNbr,nbrPages);
  714.     MoveTo(r->right - TextWidth(gBuffer,0,strlen(gBuffer)) - 8, 
  715.             r->top+FooterHeight-DescendHeight-2);
  716.     DrawText(gBuffer,0,strlen(gBuffer));
  717. }
  718.  
  719. void DrawDump(EditWindowPtr dWin, Rect *r, long sAddr, long eAddr)
  720. {
  721.     short    y;
  722.     short    hexPos;
  723.     short    asciiPos;
  724.     register short    i,ch,ch1,ch2;
  725.     long    addr;
  726.     TextFont(monaco);
  727.     TextSize(9);
  728.     TextFace(0);
  729.     TextMode(srcCopy);
  730.  
  731.     addr = sAddr - (sAddr % 16);
  732.     for (y = r->top; y < r->bottom && addr < eAddr; y += LineHeight) {
  733.         MoveTo(AddrPos,y);
  734.         if (gPrefs.decimalAddr)
  735.             sprintf(gBuffer,"%7ld: ", addr);
  736.         else
  737.             sprintf(gBuffer,"%06lX:  ", addr);
  738.         hexPos = HexStart;
  739.         asciiPos = AsciiStart;
  740.         for (i = 16; i; --i,++addr) {
  741.             if (addr >= sAddr && addr < eAddr) {
  742.                 ch = GetByte(dWin, addr);
  743.                 ch1 = ch2 = ch;
  744.                 ch1 >>= 4;
  745.                 ch2 &= 0x0F;
  746.                 gBuffer[hexPos++] = ch1 + ((ch1 < 10)? '0' : ('A'-10));
  747.                 gBuffer[hexPos++] = ch2 + ((ch2 < 10)? '0' : ('A'-10));
  748.                 gBuffer[hexPos++] = ' ';
  749.                 gBuffer[asciiPos++] = ((ch >= ' ' && ch <= gHighChar)? ch : '.');
  750.             }
  751.             else {
  752.                 gBuffer[hexPos++] = ' ';
  753.                 gBuffer[hexPos++] = ' ';
  754.                 gBuffer[hexPos++] = ' ';
  755.                 gBuffer[asciiPos++] = ' ';
  756.             }
  757.         }
  758.         gBuffer[57] = ' ';
  759.         gBuffer[58] = ' ';
  760.         MoveTo(AddrPos,y);
  761.         DrawText(gBuffer,0,75);
  762.     }
  763. }
  764.  
  765. void DrawPage(EditWindowPtr dWin)
  766. {
  767.     GrafPtr            savePort;
  768.     Rect            r;
  769.     BitMap            realBits;
  770.  
  771. #if PROFILE
  772.     _profile = 1;
  773. #endif
  774.     GetPort(&savePort);
  775.     SetPort((GrafPtr) dWin);
  776.  
  777.     realBits = ((GrafPtr) dWin)->portBits;
  778.     SetPortBits(&gBitMap);
  779.  
  780.     r = ((WindowPtr) dWin)->portRect;
  781.     r.right -= (SBarSize - 1);
  782. //    r.bottom -= (SBarSize - 1);
  783.  
  784.     if (r.right - r.left > gBitMap.bounds.right - gBitMap.bounds.left ||
  785.         r.bottom - r.top > gBitMap.bounds.bottom - gBitMap.bounds.top)
  786.         DebugStr("\pOy!");
  787.  
  788.     EraseRect(&r);
  789.  
  790.     DrawHeader(dWin, &r);
  791.  
  792.     r.top += (HeaderHeight+TopMargin+LineHeight-DescendHeight);
  793.     r.bottom -= (SBarSize+DescendHeight+BotMargin);
  794.  
  795.     DrawDump(dWin, &r, dWin->editOffset, dWin->fileSize);
  796.  
  797.     // if (dWin->endSel > dWin->startSel && 
  798.     //    dWin->endSel >= dWin->editOffset &&
  799.     //    dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  800.     //    InvertSelection(dWin);
  801.  
  802.     SetPortBits(&realBits);
  803.     SetPort(savePort);
  804.  
  805. #if PROFILE
  806.     _profile = 0;
  807. #endif
  808. }
  809.  
  810. void InvertSelection(EditWindowPtr    dWin)
  811. {
  812.     // Invert Selection
  813.     Rect    r;
  814.     long    x;
  815.     long    start,end;
  816.     short    startX,endX;
  817.     Boolean    frontFlag;
  818.  
  819.     frontFlag = ((WindowPtr) dWin == FrontWindow() &&
  820.                  dWin->oWin.active);
  821.  
  822.     if (dWin->endSel <= dWin->startSel)
  823.         return;
  824.  
  825.     start = dWin->startSel - dWin->editOffset;
  826.     if (start < 0)
  827.         start = 0;
  828.     end = (dWin->endSel-1) - dWin->editOffset;
  829.     if (end > (dWin->linesPerPage<<4)-1)
  830.         end = (dWin->linesPerPage<<4)-1;
  831.  
  832.     PenMode(patXor);
  833.     
  834.     startX = ColNbr(start);
  835.     endX = ColNbr(end);
  836.  
  837.     if (!frontFlag) {
  838.         if (LineNbr(start) < LineNbr(end)) {
  839.             // Invert Hex
  840.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  841.             r.bottom = r.top+LineHeight;
  842.             r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  843.             r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  844.  
  845.             MoveTo(AddrPos+CharPos(HexStart)-3,r.bottom);
  846.             if (gColorQDFlag)
  847.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  848.             LineTo(r.left,r.bottom);
  849.             if (gColorQDFlag)
  850.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  851.             LineTo(r.left,r.top);
  852.             if (dWin->startSel >= dWin->editOffset) {
  853.                 if (gColorQDFlag)
  854.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  855.                 LineTo(r.right,r.top);
  856.             }
  857.             else
  858.                 MoveTo(r.right,r.top);
  859.             if (gColorQDFlag)
  860.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  861.             LineTo(r.right,r.bottom);
  862.  
  863.             // Outline Box around Ascii
  864.             r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  865.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  866.             
  867.             MoveTo(AddrPos+CharPos(AsciiStart),r.bottom);
  868.             if (gColorQDFlag)
  869.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  870.             LineTo(r.left,r.bottom);
  871.  
  872.             if (gColorQDFlag)
  873.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  874.             LineTo(r.left,r.top);
  875.             if (dWin->startSel >= dWin->editOffset) {
  876.                 if (gColorQDFlag)
  877.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  878.                 LineTo(r.right,r.top);
  879.             }
  880.             else
  881.                 MoveTo(r.right,r.top);
  882.             if (gColorQDFlag)
  883.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  884.             LineTo(r.right,r.bottom);
  885.  
  886.             if (LineNbr(start) < LineNbr(end)-1) {
  887.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  888.                 r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  889.                 r.left = AddrPos+CharPos(HexStart)-3;
  890.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  891.                 MoveTo(r.left,r.top);
  892.                 if (gColorQDFlag)
  893.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  894.                 LineTo(r.left,r.bottom);
  895.                 MoveTo(r.right,r.top);
  896.                 if (gColorQDFlag)
  897.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  898.                 LineTo(r.right,r.bottom);
  899.  
  900.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  901.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  902.                 MoveTo(r.left,r.top);
  903.                 if (gColorQDFlag)
  904.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  905.                 LineTo(r.left,r.bottom);
  906.                 MoveTo(r.right,r.top);
  907.                 if (gColorQDFlag)
  908.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  909.                 LineTo(r.right,r.bottom);
  910.             }
  911.             r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  912.             r.bottom = r.top+LineHeight;
  913.             r.left = AddrPos+CharPos(HexStart)-3;
  914.             r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  915.             MoveTo(r.left,r.top);
  916.             if (gColorQDFlag)
  917.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  918.             LineTo(r.left,r.bottom);
  919.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  920.                 if (gColorQDFlag)
  921.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  922.                 LineTo(r.right,r.bottom);
  923.             }
  924.             else
  925.                 MoveTo(r.right,r.bottom);
  926.             if (gColorQDFlag)
  927.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  928.             LineTo(r.right,r.top);
  929.             if (gColorQDFlag)
  930.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  931.             LineTo(AddrPos+CharPos(HexStart)+HexPos(16)-3,r.top);
  932.  
  933.             r.left = AddrPos+CharPos(AsciiStart)-1;
  934.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  935.             MoveTo(r.left,r.top);
  936.             if (gColorQDFlag)
  937.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  938.             LineTo(r.left,r.bottom-1);
  939.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  940.                 if (gColorQDFlag)
  941.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  942.                 LineTo(r.right,r.bottom-1);
  943.             }
  944.             else
  945.                 MoveTo(r.right,r.bottom-1);
  946.             if (gColorQDFlag)
  947.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  948.             LineTo(r.right,r.top);
  949.             if (gColorQDFlag)
  950.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  951.             LineTo(AddrPos+CharPos(AsciiStart)+CharPos(16),r.top);
  952.         }
  953.         else {
  954.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  955.             r.bottom = r.top+LineHeight;
  956.             r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  957.             r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  958.             MoveTo(r.left,r.top);
  959.             if (gColorQDFlag)
  960.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  961.             LineTo(r.left,r.bottom);
  962.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  963.                 if (gColorQDFlag)
  964.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  965.                 LineTo(r.right,r.bottom);
  966.             }
  967.             else
  968.                 MoveTo(r.right,r.bottom);
  969.             if (gColorQDFlag)
  970.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  971.             LineTo(r.right,r.top);
  972.             if (dWin->startSel >= dWin->editOffset) {
  973.                 if (gColorQDFlag)
  974.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  975.                 LineTo(r.left,r.top);
  976.             }
  977.  
  978.             r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  979.             r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  980.  
  981.             MoveTo(r.left,r.top);
  982.             if (gColorQDFlag)
  983.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  984.             LineTo(r.left,r.bottom-1);
  985.             if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  986.                 if (gColorQDFlag)
  987.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  988.                 LineTo(r.right,r.bottom-1);
  989.             }
  990.             else
  991.                 MoveTo(r.right,r.bottom-1);
  992.             if (gColorQDFlag)
  993.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  994.             LineTo(r.right,r.top);
  995.             if (dWin->startSel >= dWin->editOffset) {
  996.                 if (gColorQDFlag)
  997.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  998.                 LineTo(r.left,r.top);
  999.             }
  1000.         }
  1001.     }
  1002.     else {
  1003.         if (dWin->editMode == EM_Hex) {
  1004.             if (LineNbr(start) < LineNbr(end)) {
  1005.     
  1006.                 // Invert Hex
  1007.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1008.                 r.bottom = r.top+LineHeight;
  1009.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1010.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1011.     
  1012.                 if (gColorQDFlag)
  1013.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1014.                 InvertRect(&r);
  1015.     
  1016.     
  1017.                 // Outline Box around Ascii
  1018.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1019.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  1020.                 
  1021.                 MoveTo(AddrPos+CharPos(AsciiStart),r.bottom);
  1022.                 if (gColorQDFlag)
  1023.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1024.                 LineTo(r.left,r.bottom);
  1025.     
  1026.                 if (gColorQDFlag)
  1027.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1028.                 LineTo(r.left,r.top);
  1029.                 if (dWin->startSel >= dWin->editOffset) {
  1030.                     if (gColorQDFlag)
  1031.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1032.                     LineTo(r.right,r.top);
  1033.                 }
  1034.                 else
  1035.                     MoveTo(r.right,r.top);
  1036.                 if (gColorQDFlag)
  1037.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1038.                 LineTo(r.right,r.bottom);
  1039.     
  1040.                 if (LineNbr(start) < LineNbr(end)-1) {
  1041.                     r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  1042.                     r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1043.                     r.left = AddrPos+CharPos(HexStart)-3;
  1044.                     r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1045.                     if (gColorQDFlag)
  1046.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1047.                     InvertRect(&r);
  1048.     
  1049.                     r.left = AddrPos+CharPos(AsciiStart)-1;
  1050.                     r.right = AddrPos+CharPos(AsciiStart)+CharPos(16);
  1051.                     MoveTo(r.left,r.top);
  1052.                     if (gColorQDFlag)
  1053.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1054.                     LineTo(r.left,r.bottom);
  1055.                     MoveTo(r.right,r.top);
  1056.                     if (gColorQDFlag)
  1057.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1058.                     LineTo(r.right,r.bottom);
  1059.                 }
  1060.                 r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1061.                 r.bottom = r.top+LineHeight;
  1062.                 r.left = AddrPos+CharPos(HexStart)-3;
  1063.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1064.                 if (gColorQDFlag)
  1065.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1066.                 InvertRect(&r);
  1067.     
  1068.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  1069.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1070.                 MoveTo(r.left,r.top);
  1071.                 if (gColorQDFlag)
  1072.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1073.                 LineTo(r.left,r.bottom-1);
  1074.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1075.                     if (gColorQDFlag)
  1076.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1077.                     LineTo(r.right,r.bottom-1);
  1078.                 }
  1079.                 else
  1080.                     MoveTo(r.right,r.bottom-1);
  1081.                 if (gColorQDFlag)
  1082.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1083.                 LineTo(r.right,r.top);
  1084.                 if (gColorQDFlag)
  1085.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1086.                 LineTo(AddrPos+CharPos(AsciiStart)+CharPos(16),r.top);
  1087.             }
  1088.             else {
  1089.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1090.                 r.bottom = r.top+LineHeight;
  1091.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1092.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1093.                 if (gColorQDFlag)
  1094.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1095.                 InvertRect(&r);
  1096.     
  1097.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1098.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1099.     
  1100.                 MoveTo(r.left,r.top);
  1101.                 if (gColorQDFlag)
  1102.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1103.                 LineTo(r.left,r.bottom-1);
  1104.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1105.                     if (gColorQDFlag)
  1106.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1107.                     LineTo(r.right,r.bottom-1);
  1108.                 }
  1109.                 else
  1110.                     MoveTo(r.right,r.bottom-1);
  1111.                 if (gColorQDFlag)
  1112.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1113.                 LineTo(r.right,r.top);
  1114.                 if (dWin->startSel >= dWin->editOffset) {
  1115.                     if (gColorQDFlag)
  1116.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1117.                     LineTo(r.left,r.top);
  1118.                 }
  1119.             }
  1120.         }
  1121.         else {
  1122.             // Ascii Mode!!
  1123.             //
  1124.             if (LineNbr(start) < LineNbr(end)) {
  1125.     
  1126.                 // Invert Hex
  1127.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1128.                 r.bottom = r.top+LineHeight;
  1129.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1130.                 r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1131.     
  1132.                 MoveTo(AddrPos+CharPos(HexStart)-3,r.bottom);
  1133.                 if (gColorQDFlag)
  1134.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1135.                 LineTo(r.left,r.bottom);
  1136.                 if (gColorQDFlag)
  1137.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1138.                 LineTo(r.left,r.top);
  1139.                 if (dWin->startSel >= dWin->editOffset) {
  1140.                     if (gColorQDFlag)
  1141.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1142.                     LineTo(r.right,r.top);
  1143.                 }
  1144.                 else
  1145.                     MoveTo(r.right,r.top);
  1146.                 if (gColorQDFlag)
  1147.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1148.                 LineTo(r.right,r.bottom);
  1149.     
  1150.                 // Outline Box around Ascii
  1151.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1152.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(16)-1;
  1153.                 
  1154.                 if (gColorQDFlag)
  1155.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1156.                 InvertRect(&r);
  1157.     
  1158.                 if (LineNbr(start) < LineNbr(end)-1) {
  1159.                     r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight+LineHeight;
  1160.                     r.bottom = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1161.                     r.left = AddrPos+CharPos(HexStart)-3;
  1162.                     r.right = AddrPos+CharPos(HexStart)+HexPos(16)-3;
  1163.                     MoveTo(r.left,r.top);
  1164.                     if (gColorQDFlag)
  1165.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1166.                     LineTo(r.left,r.bottom);
  1167.                     MoveTo(r.right,r.top);
  1168.                     if (gColorQDFlag)
  1169.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1170.                     LineTo(r.right,r.bottom);
  1171.     
  1172.                     r.left = AddrPos+CharPos(AsciiStart)-1;
  1173.                     r.right = AddrPos+CharPos(AsciiStart)+CharPos(16)-1;
  1174.                     if (gColorQDFlag)
  1175.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1176.                     InvertRect(&r);
  1177.                 }
  1178.                 r.top = HeaderHeight+TopMargin+LineNbr(end)*LineHeight;
  1179.                 r.bottom = r.top+LineHeight;
  1180.                 r.left = AddrPos+CharPos(HexStart)-3;
  1181.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1182.                 MoveTo(r.left,r.top);
  1183.                 if (gColorQDFlag)
  1184.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1185.                 LineTo(r.left,r.bottom);
  1186.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1187.                     if (gColorQDFlag)
  1188.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1189.                     LineTo(r.right,r.bottom);
  1190.                 }
  1191.                 else
  1192.                     MoveTo(r.right,r.bottom);
  1193.                 if (gColorQDFlag)
  1194.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1195.                 LineTo(r.right,r.top);
  1196.                 if (gColorQDFlag)
  1197.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1198.                 LineTo(AddrPos+CharPos(HexStart)+HexPos(16)-3,r.top);
  1199.     
  1200.                 r.left = AddrPos+CharPos(AsciiStart)-1;
  1201.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1202.                 if (gColorQDFlag)
  1203.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1204.                 InvertRect(&r);
  1205.             }
  1206.             else {
  1207.                 r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1208.                 r.bottom = r.top+LineHeight;
  1209.                 r.left = AddrPos+CharPos(HexStart)+HexPos(startX)-3;
  1210.                 r.right = AddrPos+CharPos(HexStart)+HexPos(endX)+HexWidth-3;
  1211.                 MoveTo(r.left,r.top);
  1212.                 if (gColorQDFlag)
  1213.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1214.                 LineTo(r.left,r.bottom);
  1215.                 if (dWin->endSel < dWin->editOffset+dWin->linesPerPage*16) {
  1216.                     if (gColorQDFlag)
  1217.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1218.                     LineTo(r.right,r.bottom);
  1219.                 }
  1220.                 else
  1221.                     MoveTo(r.right,r.bottom);
  1222.                 if (gColorQDFlag)
  1223.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1224.                 LineTo(r.right,r.top);
  1225.                 if (dWin->startSel >= dWin->editOffset) {
  1226.                     if (gColorQDFlag)
  1227.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1228.                     LineTo(r.left,r.top);
  1229.                 }
  1230.     
  1231.                 r.left = AddrPos+CharPos(AsciiStart)+CharPos(startX)-1;
  1232.                 r.right = AddrPos+CharPos(AsciiStart)+CharPos(endX)+CharWidth-1;
  1233.                 if (gColorQDFlag)
  1234.                 HiliteMode &= ~(1 << hiliteBit);    // Hilite using Hilite Color
  1235.                 InvertRect(&r);
  1236.             }
  1237.         }
  1238.     }
  1239.     PenMode(patCopy);
  1240. }
  1241.  
  1242. void PrintWindow(EditWindowPtr dWin)
  1243. {
  1244.     TPPrPort    printPort;
  1245.     TPrStatus    prStatus;
  1246.     GrafPtr        savePort;
  1247.     Boolean        ok;
  1248.     Rect        r;
  1249.     short        pageNbr,startPage,endPage,nbrPages;
  1250.     long        startAddr,endAddr,addr;
  1251.     short        linesPerPage;
  1252.  
  1253.     GetPort(&savePort);
  1254.     PrOpen();
  1255.  
  1256.     ok = PrValidate(gHPrint);
  1257.     ok = PrJobDialog(gHPrint);
  1258.     if (ok) {
  1259.         if (dWin->startSel == dWin->endSel) {
  1260.             startAddr = 0;
  1261.             endAddr = dWin->fileSize;
  1262.         }
  1263.         else {
  1264.             startAddr = dWin->startSel;
  1265.             endAddr = dWin->endSel;
  1266.         }
  1267.  
  1268.         printPort = PrOpenDoc(gHPrint,NULL,NULL);
  1269.  
  1270.         r = printPort->gPort.portRect;
  1271.         linesPerPage = ((r.bottom - FooterHeight) - TopMargin - BotMargin - HeaderHeight)/LineHeight;
  1272.         nbrPages = ((endAddr - startAddr)/16)/linesPerPage + 1;
  1273.  
  1274.         startPage = (**gHPrint).prJob.iFstPage;
  1275.         endPage = (**gHPrint).prJob.iLstPage;
  1276.         if (startPage > nbrPages) {
  1277.             PrCloseDoc(printPort);
  1278.             ErrorAlert(ES_Caution, "Selected pages are out of range 1-%d",nbrPages);
  1279.             goto ErrorExit;
  1280.         }
  1281.         addr = startAddr;
  1282.  
  1283.         if (endPage > nbrPages)
  1284.             endPage = nbrPages;
  1285.  
  1286.         for (pageNbr = 1; pageNbr <= nbrPages; ++pageNbr) {
  1287.             SetPort(&printPort->gPort);
  1288.             PrOpenPage(printPort, NULL);
  1289.     
  1290.             if (pageNbr >= startPage && pageNbr <= endPage) {
  1291.                 r = printPort->gPort.portRect;
  1292.                 DrawHeader(dWin, &r);
  1293.         
  1294.                 r.top += (HeaderHeight+TopMargin+LineHeight-DescendHeight);
  1295.                 r.bottom -= (FooterHeight + DescendHeight + BotMargin);
  1296.         
  1297.                 DrawDump(dWin, &r, addr, endAddr);
  1298.     
  1299.                 r.top = r.bottom + DescendHeight + BotMargin;
  1300.                 r.bottom = r.top + FooterHeight;
  1301.                 DrawFooter(dWin, &r, pageNbr, nbrPages);
  1302.             }
  1303.  
  1304.             addr += linesPerPage*16;
  1305.             addr -= (addr % 16);
  1306.             PrClosePage(printPort);
  1307.         }
  1308.         PrCloseDoc(printPort);
  1309.         if ((**gHPrint).prJob.bJDocLoop == bSpoolLoop && PrError() == noErr)
  1310.             PrPicFile(gHPrint, NULL, NULL, NULL, &prStatus);
  1311.     }
  1312. ErrorExit:
  1313.     PrClose();
  1314.     SetPort(savePort);
  1315. }
  1316.  
  1317. void ScrollToSelection(EditWindowPtr dWin, long pos, Boolean forceUpdate, Boolean centerFlag)
  1318. {
  1319.     long    curAddr,newAddr;
  1320.     curAddr = dWin->editOffset;
  1321.     if (pos >= curAddr && pos < curAddr+(dWin->linesPerPage<<4)) {
  1322.         if (forceUpdate) {
  1323.             DrawPage(dWin);
  1324.             UpdateOnscreen((WindowPtr) dWin);
  1325.         }
  1326.         AdjustScrollBars((WindowPtr) dWin,false);
  1327.         return;
  1328.     }
  1329.     if (centerFlag) {
  1330.         curAddr = pos - (pos % 16);
  1331.         curAddr -= 16 * (dWin->linesPerPage/2 - 1);
  1332.         // No need to adjust for limits, will be done by scroll routine
  1333.     }
  1334.     else {
  1335.  
  1336.         if (pos < curAddr) {
  1337.             // Scroll Up
  1338.             curAddr = pos;
  1339.             curAddr -= (curAddr % 16);
  1340.         }
  1341.         else {
  1342.             // Scroll Down
  1343.             curAddr = pos - (dWin->linesPerPage-1)*16;
  1344.             curAddr -= (curAddr % 16);
  1345.         }
  1346.     }
  1347.     HEditScrollToPosition(dWin, curAddr);
  1348. }
  1349.  
  1350. void OffsetSelection(EditWindowPtr dWin, short offset, Boolean shiftFlag)
  1351. {
  1352.     long    selWidth;
  1353.     Boolean    fullUpdate;
  1354.     selWidth = dWin->endSel - dWin->startSel;
  1355.     fullUpdate = shiftFlag || selWidth > 1;
  1356.     if (offset < 0) {
  1357.         if (dWin->startSel > 0) {
  1358.             dWin->startSel += offset;
  1359.             if (dWin->startSel < 0)
  1360.                 dWin->startSel = 0;
  1361.             if (!shiftFlag) {
  1362.                 dWin->endSel = dWin->startSel;
  1363.                 CursorOff((WindowPtr) dWin);
  1364.             }
  1365.             ScrollToSelection(dWin, dWin->startSel, fullUpdate, false);
  1366.             if (!shiftFlag)
  1367.                 CursorOn((WindowPtr) dWin);
  1368.         }
  1369.         else
  1370.             SysBeep(1);
  1371.     }
  1372.     else {
  1373.         if (dWin->endSel < dWin->fileSize) {
  1374.             dWin->endSel += offset;
  1375.             if (dWin->endSel > dWin->fileSize)
  1376.                 dWin->endSel = dWin->fileSize;
  1377.             if (!shiftFlag) {
  1378.                 dWin->startSel = dWin->endSel;
  1379.                 CursorOff((WindowPtr) dWin);
  1380.             }
  1381.             ScrollToSelection(dWin, dWin->endSel, fullUpdate, false);
  1382.             if (!shiftFlag)
  1383.                 CursorOn((WindowPtr) dWin);
  1384.         }
  1385.         else
  1386.             SysBeep(1);
  1387.     }
  1388. }
  1389.  
  1390. void MyProcessKey(WindowPtr theWin, EventRecord *er)
  1391. {
  1392.     short    charCode,keyCode;
  1393.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1394.  
  1395.     keyCode = (er->message & keyCodeMask) >> 8;
  1396.     charCode = (er->message & charCodeMask);
  1397.  
  1398.     if (er->modifiers & cmdKey)
  1399.         return;
  1400.  
  1401.     switch (keyCode) {
  1402.     case  0x24:            // Return
  1403.         break;
  1404.     case  0x7B:            // Left
  1405.         OffsetSelection(dWin, -1, (er->modifiers & shiftKey)>0);
  1406.         break;
  1407.     case 0x7C:            // Right
  1408.         OffsetSelection(dWin, 1, (er->modifiers & shiftKey)>0);
  1409.         break;
  1410.     case 0x7E:            // Up
  1411.         OffsetSelection(dWin, -16, (er->modifiers & shiftKey)>0);
  1412.         break;
  1413.     case 0x7D:            // Down
  1414.         OffsetSelection(dWin, 16, (er->modifiers & shiftKey)>0);
  1415.         break;
  1416.     case 0x33:            // Delete
  1417.         if (dWin->endSel > dWin->startSel) {
  1418.             ClearSelection(dWin);
  1419.         }
  1420.         else if (dWin->startSel > 0L) {
  1421.             ObscureCursor();
  1422.             --dWin->startSel;
  1423.             ClearSelection(dWin);
  1424.         }
  1425.         else
  1426.             SysBeep(1);
  1427.         break;
  1428.     default:
  1429.         // Insert Ascii Text Into Area indicated by dWin->startSel - dWin->endSel
  1430.         // Delete Current Selection if > 0
  1431.         ObscureCursor();
  1432.  
  1433.         if (dWin->editMode == EM_Ascii) {
  1434.             if (dWin->endSel != dWin->lastTypePos ||
  1435.                 dWin->startSel != dWin->lastTypePos)
  1436.                 RememberOperation(dWin, EO_Typing, &gUndoRec);
  1437.             if (dWin->endSel > dWin->startSel)
  1438.                 DeleteSelection(dWin);
  1439.             if (gOverwrite && dWin->startSel < dWin->fileSize - 1) {
  1440.                 ++dWin->endSel;
  1441.                 DeleteSelection(dWin);
  1442.             }
  1443.             InsertCharacter(dWin, charCode);
  1444.             dWin->lastTypePos = dWin->startSel;
  1445.         }
  1446.         else {
  1447.             short    hexVal;
  1448.  
  1449.             if (charCode >= '0' && charCode <= '9')
  1450.                 hexVal = charCode - '0';
  1451.             else if (charCode >= 'A' && charCode <= 'F')
  1452.                 hexVal = 0x0A + charCode - 'A';
  1453.             else if (charCode >= 'a' && charCode <= 'f')
  1454.                 hexVal = 0x0A + charCode - 'a';
  1455.             else {
  1456.                 SysBeep(1);
  1457.                 return;
  1458.             }
  1459.  
  1460.             if (dWin->endSel != dWin->lastTypePos ||
  1461.                 dWin->startSel != dWin->lastTypePos) {
  1462.                 dWin->loByteFlag = false;
  1463.                 RememberOperation(dWin, EO_Typing, &gUndoRec);
  1464.             }
  1465.             if (dWin->endSel > dWin->startSel)
  1466.                 DeleteSelection(dWin);
  1467.  
  1468.             if (dWin->loByteFlag) {
  1469.                 --dWin->startSel;
  1470.                 DeleteSelection(dWin);
  1471.                 hexVal = hexVal | (dWin->lastNybble << 4);
  1472.                 InsertCharacter(dWin, hexVal);
  1473.                 dWin->loByteFlag = false;
  1474.             }
  1475.             else {
  1476.                 if (gOverwrite && dWin->startSel < dWin->fileSize - 1) {
  1477.                     ++dWin->endSel;
  1478.                     DeleteSelection(dWin);
  1479.                 }
  1480.                 InsertCharacter(dWin, hexVal);
  1481.                 dWin->lastNybble = hexVal;
  1482.                 dWin->loByteFlag = true;
  1483.             }
  1484.             dWin->lastTypePos = dWin->startSel;
  1485.         }
  1486.         break;
  1487.     }
  1488. }
  1489.  
  1490. void CursorOff(WindowPtr theWin)
  1491. {
  1492.     if (gCursorFlag) {
  1493.         gCursorFlag = false;
  1494.         SetPort(theWin);
  1495.         InvertRect(&gCursRect);
  1496.     }
  1497. }
  1498.  
  1499. void CursorOn(WindowPtr theWin)
  1500. {
  1501.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1502.     long            start;
  1503.     Rect            r;
  1504.  
  1505.     if (!gCursorFlag &&
  1506.          dWin->startSel >= dWin->editOffset &&
  1507.         dWin->startSel < dWin->editOffset+(dWin->linesPerPage<<4)) 
  1508.     {
  1509.         gCursorFlag = true;
  1510.         SetPort(theWin);
  1511.         start = dWin->startSel - dWin->editOffset;
  1512.  
  1513.         if (dWin->editMode == EM_Hex) {
  1514.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1515.             r.bottom = r.top+LineHeight;
  1516.             r.left = AddrPos+CharPos(HexStart)+ColNbr(start)*HexWidth-3;
  1517.             r.right = r.left+2;
  1518.             InvertRect(&r);
  1519.             gCursRect = r;
  1520.         }
  1521.         else {
  1522.             r.top = HeaderHeight+TopMargin+LineNbr(start)*LineHeight;
  1523.             r.bottom = r.top+LineHeight;
  1524.             r.left = AddrPos+CharPos(AsciiStart)+ColNbr(start)*CharWidth-2;
  1525.             r.right = r.left+2;
  1526.             InvertRect(&r);
  1527.             gCursRect = r;
  1528.         }
  1529.     }
  1530. }
  1531.  
  1532. OSErr CopyFork(FSSpec *srcSpec, FSSpec *dstSpec, short forkType)
  1533. {
  1534.     short    sRefNum, dRefNum;
  1535.     OSErr    oe;
  1536.     Ptr        tBuffer;
  1537.     long    srcSize=0L,bufSize,count;
  1538.  
  1539.     tBuffer = NewPtr(32000);
  1540.  
  1541.     if (tBuffer == NULL) {
  1542.         ErrorAlert(ES_Caution, "Not Enough Memory");
  1543.         return 1;
  1544.     }
  1545.     if (forkType == FT_Resource) {
  1546.         oe = HOpenRF(srcSpec->vRefNum,srcSpec->parID,srcSpec->name,fsRdPerm,&sRefNum);
  1547.         if (oe != noErr) {
  1548.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1549.             return oe;
  1550.         }
  1551.         oe = HOpenRF(dstSpec->vRefNum,dstSpec->parID,dstSpec->name,fsWrPerm,&dRefNum);
  1552.         if (oe != noErr) {
  1553.             OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1554.             return oe;
  1555.         }
  1556.     }
  1557.     else {
  1558.         oe = HOpen(srcSpec->vRefNum,srcSpec->parID,srcSpec->name,fsRdPerm,&sRefNum);
  1559.         if (oe != noErr) {
  1560.             OSErrorAlert(ES_Caution, "HOpen", oe);
  1561.             return oe;
  1562.         }
  1563.         oe = HOpen(dstSpec->vRefNum,dstSpec->parID,dstSpec->name,fsWrPerm,&dRefNum);
  1564.         if (oe != noErr) {
  1565.             OSErrorAlert(ES_Caution, "HOpen", oe);
  1566.             return oe;
  1567.         }
  1568.     }
  1569.     GetEOF(sRefNum, &srcSize);
  1570.     SetEOF(dRefNum,0L);
  1571.     while (srcSize) {
  1572.         if (srcSize < 32000)
  1573.             bufSize = srcSize;
  1574.         else
  1575.             bufSize = 32000;
  1576.         srcSize -= bufSize;
  1577.         count = bufSize;
  1578.         oe = FSRead(sRefNum, &count, tBuffer);
  1579.         if (oe != noErr) {
  1580.             OSErrorAlert(ES_Caution,"FSRead",oe);
  1581.             goto ErrorExit;
  1582.         }
  1583.         oe = FSWrite(dRefNum, &count, tBuffer);
  1584.         if (oe != noErr) {
  1585.             OSErrorAlert(ES_Caution,"FSWrite",oe);
  1586.             goto ErrorExit;
  1587.         }
  1588.     }
  1589.     oe = noErr;
  1590. ErrorExit:
  1591.     FSClose(sRefNum);
  1592.     FSClose(dRefNum);
  1593.     DisposePtr(tBuffer);
  1594.     return oe;
  1595. }
  1596.  
  1597. void InsureNameIsUnique(FSSpec *tSpec)
  1598. {
  1599.     FInfo            fInfo;
  1600.     while (HGetFInfo(tSpec->vRefNum,
  1601.                      tSpec->parID,
  1602.                      tSpec->name, &fInfo) == noErr) {
  1603.         tSpec->name[1+MyRandom(tSpec->name[0])] = 0x80+MyRandom(64);
  1604.     }
  1605. }
  1606.  
  1607. void SaveContents(WindowPtr theWin)
  1608. {
  1609.     short            tRefNum=0;
  1610.     FSSpec            tSpec,bSpec;
  1611.     HParamBlockRec    pb;
  1612.     EditChunk        **cc;
  1613.     EditWindowPtr    dWin;
  1614.     long            count;
  1615.     OSErr            oe;
  1616.  
  1617.     dWin = (EditWindowPtr) theWin;
  1618.     if (dWin->destSpec.name[0] == 0) {
  1619.         SaveAsContents(theWin);
  1620.     }
  1621.     else {
  1622.         // Create temp file
  1623.         tSpec = dWin->destSpec;
  1624.  
  1625.         // If original file exists, write to temp folder
  1626.         if (dWin->refNum) {
  1627.             if (tSpec.name[0] < 31) {
  1628.                 tSpec.name[0]++;
  1629.                 tSpec.name[tSpec.name[0]] = 't';
  1630.             }
  1631.             else {
  1632.                 tSpec.name[31] ^= 0x10;
  1633.             }
  1634.         }
  1635.         InsureNameIsUnique(&tSpec);
  1636.  
  1637.         HDelete(tSpec.vRefNum,tSpec.parID,tSpec.name);
  1638.         oe = HCreate(tSpec.vRefNum,tSpec.parID,tSpec.name,dWin->creator, dWin->fileType);
  1639.         if (oe != noErr) {
  1640.             OSErrorAlert(ES_Caution, "HCreate", oe);
  1641.             return;
  1642.         }
  1643.  
  1644.         // Preserve creation date of orig file if it exists
  1645.         if (dWin->creationDate) {
  1646.             pb.fileParam.ioCompletion = 0l;
  1647.             pb.fileParam.ioNamePtr = tSpec.name;
  1648.             pb.fileParam.ioVRefNum = tSpec.vRefNum;
  1649.             pb.fileParam.ioDirID = tSpec.parID;
  1650.             pb.fileParam.ioFDirIndex = 0;
  1651.         
  1652.             if ((oe = PBHGetFInfo(&pb,FALSE)) != noErr) {
  1653.                 OSErrorAlert(ES_Caution, "PBHGetFInfo", oe);
  1654.                 return;
  1655.             }
  1656.             // Reset dirID which PBHGeFInfo changes...
  1657.             pb.fileParam.ioFlCrDat = dWin->creationDate;
  1658.             pb.fileParam.ioDirID = tSpec.parID;
  1659.             if ((oe = PBHSetFInfo(&pb,FALSE)) != noErr) {
  1660.                 OSErrorAlert(ES_Caution, "PBHSetFInfo", oe);
  1661.                 return;
  1662.             }
  1663.         }
  1664.         // Preserve other fork if it exists
  1665.         if (dWin->refNum)
  1666.             if (CopyFork(&dWin->fsSpec,&tSpec, !dWin->fork) != noErr)
  1667.                 return;
  1668.  
  1669.         // Open the temp file
  1670.         if (dWin->fork == FT_Resource) {
  1671.             oe = HOpenRF(tSpec.vRefNum,tSpec.parID,tSpec.name,fsWrPerm,&tRefNum);
  1672.             if (oe != noErr) {
  1673.                 OSErrorAlert(ES_Caution, "HOpenRF", oe);
  1674.                 return;
  1675.             }
  1676.         }
  1677.         else {
  1678.             oe = HOpen(tSpec.vRefNum,tSpec.parID,tSpec.name,fsWrPerm,&tRefNum);
  1679.             if (oe != noErr) {
  1680.                 OSErrorAlert(ES_Caution, "HOpen", oe);
  1681.                 return;
  1682.             }
  1683.         }
  1684.         
  1685.         // Save out to temp file
  1686.         cc = dWin->firstChunk;
  1687.         while (cc) {
  1688.             LoadChunk(dWin, cc);
  1689.             count = (*cc)->size;
  1690.             oe = FSWrite(tRefNum, &count, *(*cc)->data);
  1691.             if (oe != noErr) {
  1692.                 // !! Error Message - write error
  1693.                 FSClose(tRefNum);
  1694.                 if (oe == dskFulErr)
  1695.                     goto DiskFull;
  1696.                 OSErrorAlert(ES_Caution, "FSWrite", oe);
  1697.                 return;
  1698.             }
  1699.             cc = (*cc)->next;
  1700.         }
  1701.  
  1702.         // Close temp file
  1703.         FSClose(tRefNum);
  1704.  
  1705.         // If Original File Exists
  1706.         if (dWin->refNum) {
  1707.             // Close original file
  1708.             FSClose(dWin->refNum);
  1709.  
  1710.             bSpec = dWin->destSpec;
  1711.  
  1712.             // If it exists under current name
  1713.             if ((oe = HOpen(bSpec.vRefNum,bSpec.parID,bSpec.name,fsRdPerm,&dWin->refNum)) == noErr)
  1714.             {
  1715.                 FSClose(dWin->refNum);
  1716.  
  1717.                 if (gPrefs.backupFlag) {
  1718.                     // Delete last backup file, if it exists
  1719.                     bSpec = dWin->destSpec;
  1720.                     bSpec.name[0]++;
  1721.                     bSpec.name[bSpec.name[0]] = '~';
  1722.                     HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1723.         
  1724.                     // Rename original file to backup name
  1725.                     oe = HRename(dWin->destSpec.vRefNum,
  1726.                                  dWin->destSpec.parID,
  1727.                                  dWin->destSpec.name,
  1728.                                   bSpec.name);
  1729.                     if (oe != noErr) {
  1730.                         // Backup is probably open, just delete original
  1731.                         ErrorAlert(ES_Caution, "Can't backup original - backup file is open", oe);
  1732.                         bSpec = dWin->destSpec;
  1733.                         HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1734.                     }
  1735.                 }
  1736.                 else {
  1737.                     // Delete Original if backup flag is false
  1738.                     bSpec = dWin->destSpec;
  1739.                     HDelete(bSpec.vRefNum,bSpec.parID,bSpec.name);
  1740.                 }
  1741.             }
  1742.  
  1743.             // Rename temp file to correct name
  1744.             oe = HRename(tSpec.vRefNum,
  1745.                         tSpec.parID,
  1746.                         tSpec.name,
  1747.                         dWin->destSpec.name);
  1748.             if (oe != noErr) {
  1749.                 OSErrorAlert(ES_Stop, "HRename", oe);
  1750.             }
  1751.         }
  1752.  
  1753.         // Open newly saved file read only
  1754.         tSpec = dWin->destSpec;
  1755.         if (dWin->fork == FT_Resource) {
  1756.             oe = HOpenRF(tSpec.vRefNum,tSpec.parID,tSpec.name,fsRdPerm,&dWin->refNum);
  1757.             if (oe != noErr) {
  1758.                 OSErrorAlert(ES_Stop, "HOpenRF", oe);
  1759.             }
  1760.         }
  1761.         else {
  1762.             oe = HOpen(tSpec.vRefNum,tSpec.parID,tSpec.name,fsRdPerm,&dWin->refNum);
  1763.             if (oe != noErr) {
  1764.                 OSErrorAlert(ES_Stop, "HOpen", oe);
  1765.             }
  1766.         }
  1767.  
  1768.         // Reset Work File
  1769.         dWin->fsSpec = dWin->destSpec;
  1770.         SetWTitle((WindowPtr) dWin, dWin->fsSpec.name);
  1771.  
  1772.         dWin->workBytesWritten = 0L;
  1773.         SetEOF(dWin->workRefNum, 0L);
  1774.  
  1775.         // Flush the volume
  1776.         pb.volumeParam.ioCompletion = NULL;
  1777.         pb.volumeParam.ioNamePtr = NULL;
  1778.         pb.volumeParam.ioVRefNum = tSpec.vRefNum;
  1779.         PBFlushVol((ParmBlkPtr) &pb, FALSE);
  1780.  
  1781.         // Clear linked list
  1782.         UnloadFile(dWin);
  1783.  
  1784.         // Rebuilt linked list
  1785.         LoadFile(dWin);
  1786.  
  1787.         // Clear Dirty Flag
  1788.         dWin->dirtyFlag = false;
  1789.     }
  1790.     return;
  1791. DiskFull:
  1792.     ErrorAlert(ES_Caution, "Can't save - the disk is full.  Try freeing some space or using another disk.");
  1793.     HDelete(tSpec.vRefNum,tSpec.parID,tSpec.name);
  1794. }
  1795.  
  1796. void SaveAsContents(WindowPtr theWin)
  1797. {
  1798.     StandardFileReply    reply;
  1799.     EditWindowPtr        dWin = (EditWindowPtr) theWin;
  1800.     Str63                fileName;
  1801.     GetWTitle(theWin, fileName);
  1802.     StandardPutFile("\pFile to save:", 
  1803.                     fileName, 
  1804.                     &reply);
  1805.     if (reply.sfGood) {
  1806.         dWin->destSpec = reply.sfFile;
  1807.         dWin->creationDate = 0;
  1808.         SaveContents(theWin);
  1809.     }
  1810. }
  1811.  
  1812. void RevertContents(WindowPtr theWin)
  1813. {
  1814.     EditWindowPtr    dWin = (EditWindowPtr) theWin;
  1815.     long            newEOF;
  1816.  
  1817.     // Reset Work File
  1818.     dWin->workBytesWritten = 0L;
  1819.     SetEOF(dWin->workRefNum, 0L);
  1820.  
  1821.     // Clear linked list
  1822.     UnloadFile(dWin);
  1823.  
  1824.     // Reset EOF
  1825.     GetEOF(dWin->refNum, &newEOF);
  1826.  
  1827.     dWin->fileSize = newEOF;
  1828.  
  1829.     // Rebuilt linked list
  1830.     LoadFile(dWin);
  1831.  
  1832.     // Reset scroll offset, if necessary
  1833.     if (dWin->editOffset > dWin->fileSize -16*dWin->linesPerPage)
  1834.         dWin->editOffset = 0;
  1835.     DrawPage(dWin);
  1836.     UpdateOnscreen(theWin);
  1837. }
  1838.  
  1839.